package cn.lg.soar.system.auth.service;

import cn.lg.soar.common.util.data.DataUtil;
import cn.lg.soar.common.util.data.NumberUtil;
import cn.lg.soar.common.util.data.StringUtil;
import cn.lg.soar.common.util.lambda.LambdaUtils;
import cn.lg.soar.system.auth.entity.Org;
import cn.lg.soar.system.auth.entity.Post;
import cn.lg.soar.system.auth.model.PostSelectorDTO;
import cn.lg.soar.system.config.AuthCacheKey;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
@RefreshScope
public class PostSelectorService {

    @Autowired
    private IPostService postService;
    @Autowired
    private IOrgService orgService;

    public List<PostSelectorDTO> ids(Collection<Long> ids) {
        return toDto(postService.listByIds(ids, AuthCacheKey.POST_BY_ID));
    }

    public List<PostSelectorDTO> query(String keyword) {
        List<Post> records = postService.page(
                new Page<>(1, 500),
                Wrappers.<Post>lambdaQuery()
                        .select(Post::getId, Post::getName, Post::getOrgId)
                        .eq(Post::getDisabled, false)
                        .like(Post::getName, keyword)
        ).getRecords();
        return toDto(records);
    }

    public List<PostSelectorDTO> org(Long parentId) {
        List<PostSelectorDTO> dtos;
        if(!Objects.equals(parentId, 0L)) {
            dtos = postService.list(
                            Wrappers.<Post>lambdaQuery()
                                    .select(Post::getId, Post::getName)
                                    .eq(Post::getDisabled, false)
                                    .eq(Post::getOrgId, parentId)
                    )
                    .stream()
                    .map(PostSelectorDTO::from)
                    .collect(Collectors.toList());
            if (!dtos.isEmpty()) {
                Org org = orgService.getById(parentId);
                for (PostSelectorDTO dto : dtos) {
                    dto.setOther(org.getName());
                }
            }
        } else {
            dtos = new ArrayList<>(32);
        }
        List<Org> orgs = orgService.list(
                Wrappers.<Org>lambdaQuery()
                        .select(Org::getId, Org::getName, Org::getType, Org::getLeftNo, Org::getRightNo)
                        .eq(Org::getDisabled, false)
                        .eq(Org::getParentId, parentId)
        );
        if (!orgs.isEmpty()) {
            String idKey = StringUtil.camelToUnderscore(
                    LambdaUtils.getterToFieldName(Post::getOrgId)
            );
            Map<Long, Integer> map = postService.listMaps(
                            Wrappers.<Post>query()
                                    .select(idKey, "count(*) c")
                                    .in(idKey, orgs.stream().map(Org::getId).collect(Collectors.toList()))
                                    .groupBy(idKey)
                    ).stream()
                    .collect(Collectors.toMap(x -> DataUtil.toLong(x.get(idKey)), x -> DataUtil.toInteger(x.get("c"))));
            List<PostSelectorDTO> collect = orgs.stream()
                    .map(x -> {
                        PostSelectorDTO from = PostSelectorDTO.from(x);
                        from.setDescendantQuantity(NumberUtil.add(x.getDescendantQuantity(), map.get(x.getId())));
                        return from;
                    })
                    .collect(Collectors.toList());
            dtos.addAll(collect);
        }

        return dtos;
    }

    private List<PostSelectorDTO> toDto(List<Post> posts) {
        Set<Long> ids = posts.stream().map(Post::getOrgId).collect(Collectors.toSet());
        Map<Long, List<String>> map = orgService.nameLinkByIds(ids);

        return posts.stream()
                .map(x -> {
                    PostSelectorDTO dto = PostSelectorDTO.from(x);
                    dto.setOther(map.get(x.getOrgId()));
                    return dto;
                })
                .collect(Collectors.toList());
    }
}
